package application;


import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.logging.Logger;

import ui.SearchResultsListModel;
import ui.TimeWorkerListModel;
import workers.ClientDownloadWorker;
import workers.ClientListWorker;
import workers.ClientResumeWorker;
import workers.ClientUploadWorker;
import workers.TimedWorker;

public class Client implements Runnable{

	private final ExecutorService pool;
	//private List<Future<ClientListWorker>> futureListWorkers = new LinkedList<Future<ClientListWorker>>();
	private File rootDir;
	private Logger logger;
	private TimeWorkerListModel workers;
	
	public File getRootDir() {
		return new File(rootDir.getPath());
	}
	
	//interactive client
	public Client( int numThreads, File rootDir , TimeWorkerListModel workers ){
		this.pool = Executors.newCachedThreadPool();
		this.rootDir = rootDir;
		logger = Logger.getLogger(Server.loggerName);
		this.workers = workers;
		Logger.getLogger(Server.loggerName).info(getDescription() );
	}
	
	public Client( ExecutorService pool, File rootDir , TimeWorkerListModel workers ){
		this.pool = pool;
		this.rootDir = rootDir;
		logger = Logger.getLogger(Server.loggerName);
		this.workers = workers;
		Logger.getLogger(Server.loggerName).info(getDescription() );
	}

	
	public void Bajar( UniqueFileID archivoADescargar ){
		try {

			File storePath;
			String nombreArchivoDescargar = archivoADescargar.getFileName();
			int count = 0;					
			do{
				if( count == 0 ) storePath = new File( rootDir.getPath() + File.separatorChar + nombreArchivoDescargar );
				else storePath = new File( rootDir.getPath() + File.separatorChar + count + nombreArchivoDescargar );
				count ++;
			}while ( !storePath.createNewFile() );

			ClientDownloadWorker cdw;
			cdw = new ClientDownloadWorker( storePath, archivoADescargar ,workers);
			pool.submit( cdw );
			workers.add(cdw);
			
		} catch (IOException e) {
			e.printStackTrace();
		}			
	}
	
	public void Subir( File file, MachineID machineID ){
		
		if ( file.exists() ){
			ClientUploadWorker cuw = new ClientUploadWorker( file , machineID ,workers);
			pool.submit( cuw );
			workers.add( cuw );

		}
		else{
			logger.warning("el archivo " + file.getPath() + "no se puede enviar porque no existe" );
		}
	}
	
	public void Buscar( String tipoBusqueda, String pattern , SearchResultsListModel resultListener ) throws InterruptedException, ExecutionException{
		
		//TODO refine search logic by stopping searches when a result is found or
		//perhaps refining the logic depending on the nature of the search
	
		for (MachineID machineID : MachineIDProvider.getInstance().getAvailableMachines()) {
			ClientListWorker clw = new ClientListWorker(tipoBusqueda, pattern , machineID ,workers) ;
			pool.submit( clw, (TimedWorker)clw );
			workers.add(clw);
			clw.getChangeSupport().addPropertyChangeListener(resultListener);
		}	
	}
	
	public void reanudarDescarga ( DownloadState state ){
		ClientResumeWorker crw = new ClientResumeWorker( state, workers );
		pool.submit(crw);
		workers.add(crw);
	}
	
	@Override
	public void run() {

	}

	public String getDescription() {
		String description = "Client ExecutorService is " + pool.getClass().getName() ;
		if( pool instanceof ThreadPoolExecutor ){
			description += " with MAX_POOL_SIZE = " + ((ThreadPoolExecutor) pool).getMaximumPoolSize();
			description += " and POOL_SIZE = " + ((ThreadPoolExecutor) pool).getPoolSize();
		}
		return description;
	}
}

class MatchNameFilter implements FilenameFilter {
	
	private String name;
	public MatchNameFilter( String name ) {
		this.name = name;
	}
	
	@Override
	public boolean accept(File dir, String name) {
		return name.equals( this.name );
	}
}